故障分析 | 从 data_free 异常说起
网名“北在南方”,资深 DBA,主要负责数据库架构设计和运维平台开发工作,擅长数据库性能调优、故障诊断。
一、前言
某个客户反馈查询数据库发现 information_schema.tables
的 data_free
值突发异常,达到 13G 左右。如图:
需要排查什么原因导致的,本文梳理排查的过程和和解决问题的方法。
二、排查
2.1 分析
data_free
的含义是 表空间 ibd 文件经过写入和删除之后,留下的没有回收的碎片空间大小。data_free
值是 13G 左右, 备库正常。看结果猜测和主库上的某些请求动作有关,空洞是 MySQL 因为 sql 写入而请求分配的空间没有自动回收的结果。基于前线给的信息,没有其他思路,再看前线发的截图:
意外从 截图的 ibtmp1 文件大小找到一些线索,截图显示 ibtmp1 文件大小也是 13G ,备库则是初始值大小。
忽略红色的箭头,查看 ibtmp1 文件大小为 13G ,似乎有些头绪,
data_free
是否和 ibtmp1 有关。
2.2 验证猜想
mysql > show variables like 'innodb_temp_data_file_path';
+----------------------------+-----------------------+
| Variable_name | Value |
+----------------------------+-----------------------+
| innodb_temp_data_file_path | ibtmp1:12M:autoextend |
+----------------------------+-----------------------+
1 row in set (0.00 sec)
查看物理 ibtmp1 文件大小:
[root@tidb00 data]# du -sm ibtmp1
12 ibtmp1
沟通测试用例,让系统自动生成临时表
mysql > create table sbtest2 like sbtest1;
Query OK, 0 rows affected (0.01 sec)
mysql > insert into sbtest2(k,c,pad) select k,c ,pad from sbtest1;
Query OK, 200000 rows affected (1.18 sec)
Records: 200000 Duplicates: 0 Warnings: 0
mysql > insert into sbtest2(k,c,pad) select k,c ,pad from sbtest1;
Query OK, 200000 rows affected (1.06 sec)
mysql > insert into sbtest2(k,c,pad) select k,c ,pad from sbtest2;
Query OK, 400000 rows affected (2.49 sec)
Records: 400000 Duplicates: 0 Warnings: 0
mysql > insert into sbtest2(k,c,pad) select k,c ,pad from sbtest2;
Query OK, 800000 rows affected (6.18 sec)
Records: 800000 Duplicates: 0 Warnings: 0
再次检查 ibtmp1 文件大小 204MB
[root@tidb00 data]# du -sm ibtmp1
204 ibtmp1
mysql > SELECT FILE_NAME, TABLESPACE_NAME, ENGINE, INITIAL_SIZE, TOTAL_EXTENTS*EXTENT_SIZE
-> AS TotalSizeBytes, DATA_FREE, MAXIMUM_SIZE FROM INFORMATION_SCHEMA.FILES
-> WHERE TABLESPACE_NAME = 'innodb_temporary'\G
*************************** 1. row ***************************
FILE_NAME: ./ibtmp1
TABLESPACE_NAME: innodb_temporary
ENGINE: InnoDB
INITIAL_SIZE: 12582912
TotalSizeBytes: 213909504
DATA_FREE: 207618048 ## 和物理文件大小对应
MAXIMUM_SIZE: NULL
1 row in set (0.00 sec)
查看 I_S.tables
的data_free
的值:
查看 insert select from table 在执行过程中的确使用了临时表。
mysql > explain insert into sbtest2(k,c,pad) select k,c ,pad from sbtest2\G
*************************** 1. row ***************************
..
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: sbtest2
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1578168
filtered: 100.00
Extra: Using temporary ##
2 rows in set (0.00 sec)
Records: 200000 Duplicates: 0 Warnings: 0
三、临时表空间
3.1 介绍
innodb_temp_data_file_path
参数指定文件的路径,文件名和大小,默认配置为ibtmp1:12M:autoextend
,如果没有指定位置,临时表空间会被创建到innodb_data_home_dir
指定的路径。3.2 什么情况下会用到临时表
当 explain 查看执行计划结果的 extra 列中,如果包含 Using Temporary 就表示会用到临时表,例如如下几种常见的情况通常就会用到:
insert into tab1 select ... from tab2 。
group by 无索引字段或 group by order by 的字段不一样。
distinct 的值和 group by 的值不一样,无法利用稀疏索引。
3.3 临时表相关的参数和元数据
5.7 版本:
innodb_temp_data_file_path
default_tmp_storage_engine
internal_tmp_disk_storage_engine
8.0 版本分为会话级和全局级临时表空间
innodb_temp_tablespaces_dir #指定会话级创建临时表到BASEDIR/data/#innodb_temp
innodb_temp_data_file_path # 全局变量
internal_tmp_disk_storage_engine
用户自己创建的临时表可以通过查询 INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO
mysql > CREATE TEMPORARY TABLE t1 (c1 INT PRIMARY KEY) ENGINE=INNODB;
Query OK, 0 rows affected (0.00 sec)
mysql > SELECT * FROM INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO\G
*************************** 1. row ***************************
TABLE_ID: 54
NAME: #sqlfd5_b_0
N_COLS: 4
SPACE: 36
PER_TABLE_TABLESPACE: FALSE
IS_COMPRESSED: FALSE
1 row in set (0.00 sec)
MySQL 在执行 sql 过程中被优化器创建的表,则无法通过 INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO
直接查看。比如本文的案例。
3.4 怎么解决 ibtmp1 文件空间占用的问题
万能的重启大法, 找个合适的时间,切换数据库,重启老的主库。 通过配置
innodb_temp_data_file_path
控制ibtmp1 文件的最大值,避免表空间大小无限增加。innodb_temp_data_file_path
= ibtmp1:12M:autoextend:max:10G12M是文件的初始大小,10G是文件的最大值,超过最大值则系统会提示报错
ERROR 1114 (HY000): The table '/data/msb_5_7_31/tmp#sql_xxxxx_0' is full
参考文章
https://dev.mysql.com/doc/refman/5.7/en/innodb-temporary-tablespace.html
https://dev.mysql.com/doc/refman/8.0/en/innodb-temporary-tablespace.html
再说 order by 优化
技术分享 | 一文了解高并发限流算法
关于SQLE
爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。
类型 | 地址 |
---|---|
版本库 | https://github.com/actiontech/sqle |
文档 | https://actiontech.github.io/sqle-docs-cn/ |
发布信息 | https://github.com/actiontech/sqle/releases |
数据审核插件开发文档 | https://actiontech.github.io/sqle-docs-cn/3.modules/3.7_auditplugin/auditplugin_development.html |
更多关于 SQLE 的信息和交流,请加入官方QQ交流群:637150065...